home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch3 / CopyDDB.bas next >
Encoding:
BASIC Source File  |  1999-03-24  |  14.6 KB  |  428 lines

  1. Attribute VB_Name = "DDBHelper"
  2. Option Explicit
  3.  
  4. ' ------------------------
  5. ' Bitmap Array Information
  6. ' ------------------------
  7. Public Type RGBTriplet
  8.     rgbRed As Byte
  9.     rgbGreen As Byte
  10.     rgbBlue As Byte
  11. End Type
  12.  
  13. ' ------------------
  14. ' Bitmap Information
  15. ' ------------------
  16. Private Type BITMAP
  17.     bmType As Long
  18.     bmWidth As Long
  19.     bmHeight As Long
  20.     bmWidthBytes As Long
  21.     bmPlanes As Integer
  22.     bmBitsPixel As Integer
  23.     bmBits As Long
  24. End Type
  25. Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
  26. Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
  27. Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
  28.  
  29. Public Enum bmphErrors
  30.     bmphInvalidBitmapBits = vbObjectError + 1001
  31.     bmphPaletteError
  32. End Enum
  33.  
  34. ' -------------------
  35. ' Palette Information
  36. ' -------------------
  37. Private Type PALETTEENTRY
  38.     peRed As Byte
  39.     peGreen As Byte
  40.     peBlue As Byte
  41.     peFlags As Byte
  42. End Type
  43. Private Declare Function GetNearestPaletteIndex Lib "gdi32" (ByVal hPalette As Long, ByVal crColor As Long) As Long
  44. Private Declare Function GetPaletteEntries Lib "gdi32" (ByVal hPalette As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
  45. Private Declare Function RealizePalette Lib "gdi32" (ByVal hdc As Long) As Long
  46. Private Declare Function GetSystemPaletteEntries Lib "gdi32" (ByVal hdc As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
  47. Private Declare Function ResizePalette Lib "gdi32" (ByVal hPalette As Long, ByVal nNumEntries As Long) As Long
  48. Private Declare Function SetPaletteEntries Lib "gdi32" (ByVal hPalette As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
  49. Private Const MAX_PALETTE_SIZE = 256
  50. Private Const PC_NOCOLLAPSE = &H4    ' Do not match color existing entries.
  51.  
  52. ' -------------------------------
  53. ' System Capabilities Information
  54. ' -------------------------------
  55. Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
  56. Private Const NUMRESERVED = 106  ' Number of reserved entries in system palette.
  57. Private Const SIZEPALETTE = 104  ' Size of system palette.
  58. ' Load the control's palette so it matches the
  59. ' system palette.
  60. Private Sub MatchColorPalette(ByVal pic As PictureBox)
  61. Dim log_hpal As Long
  62. Dim sys_pal(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
  63. Dim orig_pal(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
  64. Dim i As Integer
  65. Dim sys_pal_size As Long
  66. Dim num_static_colors As Long
  67. Dim static_color_1 As Long
  68. Dim static_color_2 As Long
  69.  
  70.     ' Make sure pic has the foreground palette.
  71.     pic.ZOrder
  72.     RealizePalette pic.hdc
  73.     DoEvents
  74.  
  75.     ' Get system palette size and # static colors.
  76.     sys_pal_size = GetDeviceCaps(pic.hdc, SIZEPALETTE)
  77.     num_static_colors = GetDeviceCaps(pic.hdc, NUMRESERVED)
  78.     static_color_1 = num_static_colors \ 2 - 1
  79.     static_color_2 = sys_pal_size - num_static_colors \ 2
  80.  
  81.     ' Get the system palette entries.
  82.     GetSystemPaletteEntries pic.hdc, 0, _
  83.         sys_pal_size, sys_pal(0)
  84.  
  85.     ' Make the logical palette as big as possible.
  86.     log_hpal = pic.Picture.hpal
  87.     If ResizePalette(log_hpal, sys_pal_size) = 0 Then
  88.         Err.Raise bmphPaletteError, _
  89.             "DDBHelper.MatchColorPalette", _
  90.             "Error matching bitmap palette"
  91.     End If
  92.  
  93.     ' Blank the non-static colors.
  94.     For i = 0 To static_color_1
  95.         orig_pal(i) = sys_pal(i)
  96.     Next i
  97.     For i = static_color_1 + 1 To static_color_2 - 1
  98.         With orig_pal(i)
  99.             .peRed = 0
  100.             .peGreen = 0
  101.             .peBlue = 0
  102.             .peFlags = PC_NOCOLLAPSE
  103.         End With
  104.     Next i
  105.     For i = static_color_2 To 255
  106.         orig_pal(i) = sys_pal(i)
  107.     Next i
  108.     SetPaletteEntries log_hpal, 0, sys_pal_size, orig_pal(0)
  109.  
  110.     ' Insert the non-static colors.
  111.     For i = static_color_1 + 1 To static_color_2 - 1
  112.         orig_pal(i) = sys_pal(i)
  113.         orig_pal(i).peFlags = PC_NOCOLLAPSE
  114.     Next i
  115.     SetPaletteEntries log_hpal, static_color_1 + 1, static_color_2 - static_color_1 - 1, orig_pal(static_color_1 + 1)
  116.  
  117.     ' Realize the new palette.
  118.     RealizePalette pic.hdc
  119. End Sub
  120. ' Return a binary representation of the byte.
  121. ' This helper function is useful for understanding
  122. ' byte values.
  123. Public Function BinaryByte(ByVal value As Byte) As String
  124. Dim i As Integer
  125. Dim txt As String
  126.  
  127.     For i = 1 To 8
  128.         If value And 1 Then
  129.             txt = "1" & txt
  130.         Else
  131.             txt = "0" & txt
  132.         End If
  133.         value = value \ 2
  134.     Next i
  135.  
  136.     BinaryByte = txt
  137. End Function
  138.  
  139. ' Load the bits from this PictureBox into a
  140. ' two-dimensional array of RGB values. Set
  141. ' bits_per_pixel to be the number of bits per pixel.
  142. Public Sub GetBitmapPixels(ByVal pic As PictureBox, ByRef pixels() As RGBTriplet, ByRef bits_per_pixel As Integer)
  143. ' Uncomment the following to make the routine
  144. ' display information about the bitmap.
  145. ' #Const DEBUG_PRINT_BITMAP = True
  146.  
  147. Dim hbm As Long
  148. Dim bm As BITMAP
  149. Dim l As Single
  150. Dim t As Single
  151. Dim old_color As Long
  152. Dim bytes() As Byte
  153. Dim num_pal_entries As Long
  154. Dim pal_entries(0 To MAX_PALETTE_SIZE - 1) As PALETTEENTRY
  155. Dim pal_index As Integer
  156. Dim wid As Integer
  157. Dim hgt As Integer
  158. Dim X As Integer
  159. Dim Y As Integer
  160. Dim two_bytes As Long
  161.  
  162.     ' Get the bitmap information.
  163.     hbm = pic.Image
  164.     GetObject hbm, Len(bm), bm
  165.     bits_per_pixel = bm.bmBitsPixel
  166.  
  167.     ' If bits_per_pixel is 16, see if it's really
  168.     ' 15 or 16 bits per pixel.
  169.     If bits_per_pixel = 16 Then
  170.         ' Make the upper left pixel white.
  171.         l = pic.ScaleLeft
  172.         t = pic.ScaleTop
  173.         old_color = pic.Point(l, t)
  174.         pic.PSet (l, t), vbWhite
  175.  
  176.         ' See what color was set.
  177.         ReDim bytes(0 To 0, 0 To 0)
  178.         GetBitmapBits hbm, 2, bytes(0, 0)
  179.         If (bytes(0, 0) And &H80) = 0 Then
  180.             ' It's really a 15-bit image.
  181.             bits_per_pixel = 15
  182.         End If
  183.  
  184.         ' Restore the pixel's original color.
  185.         pic.PSet (l, t), old_color
  186.     End If
  187.  
  188.     #If DEBUG_PRINT_BITMAP Then
  189.         Debug.Print "*** BITMAP Data ***"
  190.         Debug.Print "bmType       "; bm.bmType
  191.         Debug.Print "bmWidth      "; bm.bmWidth
  192.         Debug.Print "bmHeight     "; bm.bmHeight
  193.         Debug.Print "bmWidthBytes "; bm.bmWidthBytes
  194.         Debug.Print "bmPlanes     "; bm.bmPlanes
  195.         Debug.Print "bmBitsPixel  "; bm.bmBitsPixel
  196.         Debug.Print "BitsPerPixel "; bits_per_pixel
  197.     #End If
  198.  
  199.     ' Get the bits.
  200.     If (bits_per_pixel = 8) Or _
  201.        (bits_per_pixel = 15) Or _
  202.        (bits_per_pixel = 16) Or _
  203.        (bits_per_pixel = 24) Or _
  204.        (bits_per_pixel = 32) _
  205.     Then
  206.         ' Get the bits.
  207.         ReDim bytes(0 To bm.bmWidthBytes - 1, 0 To bm.bmHeight - 1)
  208.         GetBitmapBits hbm, bm.bmWidthBytes * bm.bmHeight, bytes(0, 0)
  209.     Else
  210.         ' We don't know how to read this format.
  211.         Err.Raise bmphInvalidBitmapBits, _
  212.             "DDBHelper.GetBitmapPixels", _
  213.             "Invalid number of bits per pixel: " _
  214.             & Format$(bits_per_pixel)
  215.     End If
  216.  
  217.     ' Create the pixels array.
  218.     wid = bm.bmWidth
  219.     hgt = bm.bmHeight
  220.     ReDim pixels(0 To wid - 1, 0 To hgt - 1)
  221.     Select Case bits_per_pixel
  222.         Case 8
  223.             ' Match pic's palette to the system palette.
  224.             MatchColorPalette pic
  225.  
  226.             ' Get the image's palette entries.
  227.             num_pal_entries = GetPaletteEntries( _
  228.                 pic.Picture.hpal, 0, _
  229.                 MAX_PALETTE_SIZE, pal_entries(0))
  230.  
  231.             ' Get the RGB color components.
  232.             For Y = 0 To hgt - 1
  233.                 For X = 0 To wid - 1
  234.                     With pixels(X, Y)
  235.                         pal_index = bytes(X, Y)
  236.                         .rgbRed = pal_entries(pal_index).peRed
  237.                         .rgbGreen = pal_entries(pal_index).peGreen
  238.                         .rgbBlue = pal_entries(pal_index).peBlue
  239.                     End With
  240.                 Next X
  241.             Next Y
  242.  
  243.         Case 15
  244.             For Y = 0 To hgt - 1
  245.                 For X = 0 To wid - 1
  246.                     With pixels(X, Y)
  247.                         ' Get the combined 2 bytes for this pixel.
  248.                         two_bytes = bytes(X * 2, Y) + bytes(X * 2 + 1, Y) * 256&
  249.  
  250.                         ' Separate the pixel's components.
  251.                         .rgbBlue = two_bytes Mod 32
  252.                         two_bytes = two_bytes \ 32
  253.                         .rgbGreen = two_bytes Mod 32
  254.                         two_bytes = two_bytes \ 32
  255.                         .rgbRed = two_bytes
  256.                     End With
  257.                 Next X
  258.             Next Y
  259.  
  260.         Case 16
  261.             For Y = 0 To hgt - 1
  262.                 For X = 0 To wid - 1
  263.                     With pixels(X, Y)
  264.                         ' Get the combined 2 bytes for this pixel.
  265.                         two_bytes = bytes(X * 2, Y) + bytes(X * 2 + 1, Y) * 256&
  266.  
  267.                         ' Separate the pixel's components.
  268.                         .rgbBlue = two_bytes Mod 32
  269.                         two_bytes = two_bytes \ 32
  270.                         .rgbGreen = two_bytes Mod 64
  271.                         two_bytes = two_bytes \ 64
  272.                         .rgbRed = two_bytes
  273.                     End With
  274.                 Next X
  275.             Next Y
  276.  
  277.         Case 24
  278.             For Y = 0 To hgt - 1
  279.                 For X = 0 To wid - 1
  280.                     With pixels(X, Y)
  281.                         .rgbBlue = bytes(X * 3, Y)
  282.                         .rgbGreen = bytes(X * 3 + 1, Y)
  283.                         .rgbRed = bytes(X * 3 + 2, Y)
  284.                     End With
  285.                 Next X
  286.             Next Y
  287.  
  288.         Case 32
  289.             For Y = 0 To hgt - 1
  290.                 For X = 0 To wid - 1
  291.                     With pixels(X, Y)
  292.                         .rgbBlue = bytes(X * 4, Y)
  293.                         .rgbGreen = bytes(X * 4 + 1, Y)
  294.                         .rgbRed = bytes(X * 4 + 2, Y)
  295.                     End With
  296.                 Next X
  297.             Next Y
  298.  
  299.     End Select
  300. End Sub
  301. ' Set the bits in this PictureBox using a 0-based
  302. ' two-dimensional array of RGBTriplets. The pixels must
  303. ' have the right dimensions to match the picture.
  304. Public Sub SetBitmapPixels(ByVal pic As PictureBox, ByVal bits_per_pixel As Integer, pixels() As RGBTriplet)
  305. Dim wid_bytes As Long
  306. Dim wid As Integer
  307. Dim hgt As Integer
  308. Dim X As Integer
  309. Dim Y As Integer
  310. Dim bytes() As Byte
  311. Dim hpal As Long
  312. Dim two_bytes As Long
  313.  
  314.     ' See how big the image must be.
  315.     wid = UBound(pixels, 1) + 1
  316.     hgt = UBound(pixels, 2) + 1
  317.  
  318.     ' See how many bytes per row we need.
  319.     Select Case bits_per_pixel
  320.         Case 8
  321.             wid_bytes = wid
  322.         Case 15, 16
  323.             wid_bytes = wid * 2
  324.         Case 24
  325.             wid_bytes = wid * 3
  326.         Case 32
  327.             wid_bytes = wid * 4
  328.         Case Else
  329.             ' We don't understand this format.
  330.             Err.Raise bmphInvalidBitmapBits, _
  331.                 "DDBHelper.GetBitmapPixels", _
  332.                 "Invalid number of bits per pixel: " _
  333.                 & Format$(bits_per_pixel)
  334.     End Select
  335.  
  336.     ' Make sure it's even.
  337.     If wid_bytes Mod 2 = 1 Then wid_bytes = wid_bytes + 1
  338.  
  339.     ' Create the bitmap bytes array.
  340.     ReDim bytes(0 To wid_bytes - 1, 0 To hgt - 1)
  341.  
  342.     ' Set the bitmap byte values.
  343.     Select Case bits_per_pixel
  344.         Case 8
  345.             ' Use the nearest palette entries.
  346.             hpal = pic.Picture.hpal
  347.  
  348.             ' Get the RGB color components.
  349.             For Y = 0 To hgt - 1
  350.                 For X = 0 To wid - 1
  351.                     With pixels(X, Y)
  352.                         bytes(X, Y) = (&HFF And _
  353.                             GetNearestPaletteIndex(hpal, _
  354.                                 RGB(.rgbRed, .rgbGreen, .rgbBlue) _
  355.                             + &H2000000))
  356.                     End With
  357.                 Next X
  358.             Next Y
  359.  
  360.         Case 15
  361.             For Y = 0 To hgt - 1
  362.                 For X = 0 To wid - 1
  363.                     With pixels(X, Y)
  364.                         ' Keep the values in bounds.
  365.                         If .rgbRed > &H1F Then .rgbRed = &H1F
  366.                         If .rgbGreen > &H1F Then .rgbGreen = &H1F
  367.                         If .rgbBlue > &H1F Then .rgbBlue = &H1F
  368.  
  369.                         ' Combine the values in 2 bytes.
  370.                         two_bytes = .rgbBlue + 32 * (.rgbGreen + CLng(.rgbRed) * 32)
  371.  
  372.                         ' Set the byte values.
  373.                         bytes(X * 2, Y) = (two_bytes Mod 256) And &HFF
  374.                         bytes(X * 2 + 1, Y) = (two_bytes \ 256) And &HFF
  375.                     End With
  376.                 Next X
  377.             Next Y
  378.  
  379.         Case 16
  380.             For Y = 0 To hgt - 1
  381.                 For X = 0 To wid - 1
  382.                     With pixels(X, Y)
  383.                         ' Keep the values in bounds.
  384.                         If .rgbRed > &H1F Then .rgbRed = &H1F
  385.                         If .rgbGreen > &H3F Then .rgbGreen = &H3F
  386.                         If .rgbBlue > &H1F Then .rgbBlue = &H1F
  387.  
  388.                         ' Combine the values in 2 bytes.
  389.                         two_bytes = .rgbBlue + 32 * (.rgbGreen + CLng(.rgbRed) * 64)
  390.  
  391.                         ' Set the byte values.
  392.                         bytes(X * 2, Y) = (two_bytes Mod 256) And &HFF
  393.                         bytes(X * 2 + 1, Y) = (two_bytes \ 256) And &HFF
  394.  
  395.                     End With
  396.                 Next X
  397.             Next Y
  398.  
  399.         Case 24
  400.             For Y = 0 To hgt - 1
  401.                 For X = 0 To wid - 1
  402.                     With pixels(X, Y)
  403.                         bytes(X * 3, Y) = .rgbBlue
  404.                         bytes(X * 3 + 1, Y) = .rgbGreen
  405.                         bytes(X * 3 + 2, Y) = .rgbRed
  406.                     End With
  407.                 Next X
  408.             Next Y
  409.  
  410.         Case 32
  411.             For Y = 0 To hgt - 1
  412.                 For X = 0 To wid - 1
  413.                     With pixels(X, Y)
  414.                         bytes(X * 4, Y) = .rgbBlue
  415.                         bytes(X * 4 + 1, Y) = .rgbGreen
  416.                         bytes(X * 4 + 2, Y) = .rgbRed
  417.                     End With
  418.                 Next X
  419.             Next Y
  420.  
  421.     End Select
  422.  
  423.     ' Set the picture's bitmap bits.
  424.     SetBitmapBits pic.Image, wid_bytes * hgt, _
  425.         bytes(0, 0)
  426.     pic.Refresh
  427. End Sub
  428.